<?php
namespace App\Services;
use App\Events\FlowChangeEvent;
use App\Models\Admin;
use App\Models\Appoint;
use App\Models\Car;
use App\Models\Config;
use App\Models\Credit;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redis;

class CarService {

    public static function getByStatusTotal($status = Appoint::STATUS_SIGN_IN, $date = null) {
        if (!$date)
            $date = date('Y-m-d');

        return Car::where('status', $status)->where('cur_date', $date)->count();
    }
    /**
     * 前方排队数： 排队号码- 装车撬位数-待装区位置数 - 签退总数 - 未按时进场违约总数
     * @param $car_id
     * @return mixed
     */
    public static function getFrontQueueTotal($car) {
        $order_sn = $car->order_sn;
        $total = Config::getTotal();
        if (!$order_sn)
            return " ";
        $sign_out_total = Appoint::where('date', $car->cur_date)->where('status', 3)->count();
        $not_in = Credit::where('type', Credit::STATUS_NOT_IN)->where('date', $car->cur_date)->count();
        $result = $order_sn - $total - $sign_out_total - $not_in;
        return $result > 0 ? $result : 0;
    }

   public static function flow($input, $operator_id, $from = 1, $user = null) {
//        \Log::info($operator_id . "  " . var_export($input, true));
       $cache_key = "appoint:lock:" . date('Y-m-d') . 'car_id' .  $input['car_id'];
       if (Redis::setnx($cache_key, 1)) {
           Redis::expire($cache_key, 2);
           try {

               $car = Car::find($input['car_id']);
               if (!$car) {
                   throw new \Exception("car_id 不存在", 200);
               }
//               if ($car->cur_date != date('Y-m-d')) {
//                   throw new \Exception('预约车辆不在当日计划中', 200);
//               }
               if ($car->status == $input['status']) {
                   throw new \Exception("你已操作成功，请刷新页面勿重新操作", 200);
               }
               if ($input['status'] == Car::STATUS_SIGN_IN) {
                    if (!in_array($car->status,  [Car::STATUS_APPOINT_ED, Car::STATUS_NOTIFY])) {
                        throw new \Exception("当前状态不允许签到", 200);
                    }
               } else {
                   if ($car->status > $input['status']) {
                       throw new \Exception("status不能反着操作", 200);
                   }
               }

               if ($input['status'] == Appoint::STATUS_SIGN_IN) {
                   if (!in_array($car->status, [Car::STATUS_APPOINT_ED, Car::STATUS_NOTIFY])) {
                       throw new \Exception("当前状态不允许签到", 200);
                   }
                   $car->sign_in_user_id = $operator_id;
                   $car->last_status = $car->status;
                   $car->sign_in_at = date('Y-m-d H:i:s');
               }

               if ($input['status'] == Appoint::STATUS_APPOINT) {
                   //判断是否在预约时间之内
                   $appoint_time = Config::getAppointTime();
                   if (!$appoint_time['is_show']) {
                       throw new \Exception('暂未开启预约', 200);
                   }

                   if ($from != 'admin') {
                       $delay = ($user->not_sign_in_times + $user->not_sign_out_times) * $appoint_time['punish'];
                       $second = strtotime($appoint_time['start_at']) + $delay;
                       if ($second > time()) {
                           throw new \Exception('预约延迟，请查看“我的”信息页通知公告。', 200);
                       }
                   }

                   $cache_key_date = 'cache_key_appoint_' . $car->cur_date;
                   $car->order_sn  = Redis::incr($cache_key_date);
//                   \Log::info('order_sn ' . $car->order_sn . ' car_id ' . $input['car_id']);
                   //获取最近一条订单号
//                   $order_sn = Car::where('cur_date', date('Y-m-d'))
//                       ->where('date', '<=', date('Y-m-d H:i:s'))
//                       ->orderBy('order_sn', 'desc')
//                       ->value('order_sn');
//                   $car->order_sn = $order_sn + 1;
                   if ($from == 1)
                       $car->user_id = $operator_id;

                   $car->appoint_user_id = $operator_id;
                   $car->appoint_at = date('Y-m-d H:i:s');
               }
               if ($input['status'] == Appoint::STATUS_SIGN_OUT) {
                   if ($car->status != '2') {
                       throw new \Exception("请先签到才能签退", 200);
                   }
                   $car->sign_out_user_id = $operator_id;
                   $car->sign_out_at = date('Y-m-d H:i:s');
               }
               $car->status = $input['status'];
               $car->save();
               Appoint::create([
                   'car_id' => $input['car_id'],
                   'status' => $input['status'],
                   'date' => $car->cur_date,
                   'from' => $from,
                   'operator_id' => $operator_id
               ]);
               Redis::del($cache_key);
           } catch (\Exception $e) {
               if ($e->getCode() != 200) {
                   \Log::error($e);
               }
               Redis::del($cache_key);
               throw new \Exception($e->getMessage(), 200);
           }
           in_array($car->status, [Car::STATUS_APPOINT_ED,Car::STATUS_SIGN_IN]) && event(new FlowChangeEvent($car->id, $car->status));
       } else {
           throw new \Exception("你车友已在操作，稍候再试", 200);
       }
   }


   public static function search_list(Request $request) {
       $carrier_unit = $request->carrier_unit;
       $delivery_unit = $request->delivery_unit;
       $driver = $request->driver;
       $supercargo = $request->supercargo;
       $date = $request->date ?? date("Y-m-d");
       $type = $request->type ?? 1; //  1：今日 2：待装车计划 3：历史装车计划
       $role = $request->role;
       $title = $request->title;
       $status = $request->status ?? -1;
       $trailer_num = $request->trailer_num;
       $car_num = $request->car_num;
       $from = $request->from ?? 'admin';
       $is_punish = $request->is_punish ?? -1; //违约

       if ($status == -1) {
           $arr_status = [];
       } else {
           $arr_status = explode(",", $status);
       }

       //装车计划
       $list = Car::when($carrier_unit, function ($q) use($carrier_unit) {
           $q->where('carrier_unit', 'like', '%' . $carrier_unit . '%');
       })->when($delivery_unit, function ($q) use($delivery_unit) {
           $q->where('delivery_unit', 'like', '%' . $delivery_unit . '%');
       })->when(!empty($arr_status), function ($q) use($arr_status) {
           $q->whereIn('status', $arr_status);
       })->when($driver, function ($q) use($driver) {
           $q->where('driver', 'like', '%' . $driver . '%');
       })->when($supercargo, function ($q) use($supercargo) {
           $q->where('supercargo', 'like', '%' . $supercargo . '%');
       })->when($trailer_num, function ($q) use($trailer_num) {
           $q->where('trailer_num', 'like', '%' . $trailer_num . '%');
       })->when($is_punish != -1, function ($q) use($is_punish) {
           $q->where('is_punish', $is_punish);
       })->when($car_num, function ($q) use($car_num) {
           $q->where('car_num', 'like', '%' . $car_num . '%');
       })->when($role, function ($q) use($role, $title) {
           $q->where(function ($sub) use($title, $role){
               if ($role == 1) {
                   $sub->where('driver', $title)->orWhere('supercargo', $title);
               } else if($role == 2) {
                   $sub->where('delivery_unit', $title);
               } else {
                   $sub->where('carrier_unit', $title);
               }
           });
       })->when($type, function ($q) use($type, $date, $from) {
           if ($type == 2) {
               if ($from == 'admin') {
                   $q->where('is_publish', 0);
               } else {
                    $q->where(function ($query) {
                        $today = date('Y-m-d');
                        $tomorrow = date("Y-m-d",strtotime("+1 day"));
                        $query->where('cur_date', $today)->orWhere('cur_date', $tomorrow);
                    })->where('is_publish', 1);
               }
           } else if($type == 1) { //今日
//               $q->where('date', '<=', date('Y-m-d H:i:s'))->where('cur_date', date('Y-m-d'))->where('is_publish', 1);
               $q->where('cur_date', $date)->where('is_publish', 1);
           } else { //历史
               $q->where('cur_date', $date)->where('is_publish', 1);
           }
       })->when($from == 'admin', function ($q) {
           $field = ['nickname', 'title'];
           $q->withCertain('appoint_user', $field)->withCertain('sign_in_user', $field)->withCertain('sign_out_user', $field)->withCertain('cancel_user', $field)
               ->orderBy('order_sn', 'desc');
       })->paginate(\request('per_page', 20));

       if ($type == 1 && $from == 'api') {
           $first = $list->first();
           if ($first) {
               $sign_in_total = Car::get_sign_in_total($first->cur_date);
               $cache_key_date = 'cache_key_appoint_' . $first->cur_date;
               $latest_order_sn  = Redis::get($cache_key_date) ?: 0;

               $cache_key_date = 'cache_key_notify_' . $first->cur_date;
               $latest_notify_order_sn = Redis::get($cache_key_date) ?? 0;

               foreach ($list as &$item) {
                   $front_queue_total= self::getFrontQueueTotal($item);
                   $item->sign_in_total = $sign_in_total;
                   $item->front_queue_total = $front_queue_total;
                   $item->latest_order_sn = $latest_order_sn;
                   $item->latest_notify_order_sn = $latest_notify_order_sn ?: 0;
                   $item->queue_num_show = $request->queue_num_show ?? 0;
               }
           }
       } else if($from == 'admin') {
           foreach ($list as &$item) {
               if ($item->appoint_user_id < 0) {
                   $item->admin_appoint_username = Admin::fetch_one(abs($item->appoint_user_id))->username;
               }
               if ($item->sign_in_user_id < 0) {
                   $item->admin_sign_in_username = Admin::fetch_one(abs($item->sign_in_user_id))->username;
               }
               if ($item->sign_out_user_id < 0) {
                   $item->admin_sign_out_username = Admin::fetch_one(abs($item->sign_out_user_id))->username;
               }
               if ($item->cancel_user_id < 0) {
                   $item->admin_cancel_username = Admin::fetch_one(abs($item->cancel_user_id))->username;
               }
           }
       }
       return $list;
   }

   public static function getOpenIds($supercargo, $delivery_unit) {
        $list = User::where('title', 'like', '%'.$supercargo.'%')
            ->orWhere('title', 'like', '%'.$delivery_unit.'%')->select('weixin_openid', 'title')->get();

        $temp = [];
        if ($list) {
            $arr = $list->toArray();
            foreach ($arr as $item) {
                $temp[$item['weixin_openid']] = $item['title'];
            }
        }
        return $temp;
//        return $list->all();
   }

   public static function getWaitSignInOpenId() {
       $car = Car::where('cur_date', date('Y-m-d'))
           ->where('status', Appoint::STATUS_APPOINT)->where('sign_in_notice', 0)->orderby('order_sn', 'asc')->first();
        if (!$car)
            return null;

       Car::where('id', $car->id)->update([
           'sign_in_notice' => 1
       ]);
       return $car;

       $list = self::getOpenIds($car->driver, $car->supercargo);
       return ['openIds' => $list, 'order_sn' => $car->order_sn, 'car_num' => $car->car_num];
   }


   // 人员排队序号-厂区容量-签退人数 -违约发生次数 小于等于0就通知进厂
   public static function signInNotify($cur_date = null) {
        if (!$cur_date)
            $cur_date = date('Y-m-d');

       $template = new PublishTemplateService();
       $total = Config::getTotal();
       $sign_out_total = Appoint::where('date', $cur_date)->where('status', 3)->count();
       $list = Car::where('cur_date', $cur_date)->where('status', Car::STATUS_APPOINT_ED)->where('order_sn', '>', 0)
           ->where('user_id', '>', 0)->where('sign_in_notice', 0)->orderBy('order_sn', 'asc')->get();
       //@todo 违约
       $weiyue = Credit::where('date', $cur_date)->count();

       if ($list) {
           $click_min = Config::getSignInClockTime();
           foreach ($list as $item) {
                $str= $item->order_sn - $sign_out_total - $weiyue;
                if ($str <= $total) {
                    $user_2 = User::find($item->user_id);
                    $item->sign_in_notice = 1;
                    $item->status = Car::STATUS_NOTIFY;
                    $item->notify_at = date('Y-m-d H:i:s');
                    $item->sign_in_end_at = date('Y-m-d H:i:s', time() + $click_min *  60);
                    $item->save();

                    $cache_key_date = 'cache_key_notify_' . $item->cur_date;
                    Redis::set($cache_key_date, $item->order_sn);

                    $template->callSignIn($user_2->weixin_openid, $item->car_num, $item->order_sn);
                }
           }
       }
   }

   public static function canSignIn() {
       $total = Config::getTotal();
       $appoint_total = Appoint::where('date', date('Y-m-d'))->where('status', 1)->count();
       $sign_out_total = Appoint::where('date', date('Y-m-d'))->where('status', 3)->count();
       $sign_in_total = $appoint_total - $sign_out_total;
//       $sign_in_total = self::getByStatusTotal(Appoint::STATUS_SIGN_IN);
       return $total > $sign_in_total;
   }

}
